package au.edu.qut.bpm.genbinder.genetic.genesis;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import au.edu.qut.bpm.genbinder.models.Activity;
import au.edu.qut.bpm.genbinder.models.Case;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;
import au.edu.qut.bpm.genbinder.models.Resource;

public class LogRepairFactory extends LogAbstractFactory {
	
	public LogRepairFactory(ConcreteEventLog log) {
		super(log);
	}

	@Override
	public ConcreteEventLog generateRandomCandidate() {
		ConcreteEventLog newLog = new ConcreteEventLog(templateLog);
		Set<Activity> scheduledActivities = new HashSet<Activity>();
		ArrayList<Case> alCase = new ArrayList<Case>(newLog.getAbstractLog().getCases());
		
		//Collections.shuffle(alCase);
		
		for (Case c : alCase) {
			//Random random = new Random();
			//int randomInt = random.nextInt(10);
			long gap = 0;//randomInt;
			
			/*boolean first = true;
			long placeAfter = 0 + gap;
			if (first)
				placeAfter = c.getArrival() + gap;
			first = false;*/
			long placeAfter = c.getArrival();
			for (Activity a : c.getOrderedTrace()) {

				List<Activity> listAct = new ArrayList<Activity>(newLog.getAllActivity());
				Set<Resource> resourceSet = new HashSet<Resource>(cel.getActivityResources(a));
				boolean resUtil = newLog.checkWhetherResourceIsUtilizedWithin(placeAfter, placeAfter + newLog.getActivityDuration(a), listAct, resourceSet.iterator().next());

				if (resUtil) {
					boolean scheduled = false;
					
					long latestEndTime = 0;
					for (Activity oa : scheduledActivities) {
						if (newLog.getActivityEnd(oa) > latestEndTime) {
							latestEndTime = newLog.getActivityEnd(oa);
						}
						if (newLog.getActivityEnd(oa) >= placeAfter) {
							resUtil = newLog.checkWhetherResourceIsUtilizedWithin(newLog.getActivityEnd(oa), newLog.getActivityEnd(oa) + newLog.getActivityDuration(a), listAct, resourceSet.iterator().next());
							
							if (!resUtil) {
								newLog.setActivityStart(a, newLog.getActivityEnd(oa));
								newLog.setActivityResources(a, resourceSet);
								scheduled = true;
								break;
							}
						}
					}
					if (!scheduled)
						System.err.println("An activity could not be greedily scheduled: you should panic");
				} else {
					newLog.setActivityStart(a, placeAfter);
					newLog.setActivityResources(a, resourceSet);
				}
				//Random random2 = new Random();
				//int randomInt2 = random2.nextInt(10);
				long gap2 = 0;//randomInt2;
				
				placeAfter = newLog.getActivityEnd(a) + gap2;
				scheduledActivities.add(a);
			}
		}
		return newLog;

	}
	
	@Override
	public ConcreteEventLog generateRandomCandidate(boolean performSafetyCheck, Random rng) {
		return generateRandomCandidate(rng);
	}

	@Override
	public ConcreteEventLog generateRandomCandidate(Random rng) {
		return generateRandomCandidate();
	}
}
